#define _GNU_SOURCE
#include "app_bt.h"
#include <string.h>
#include "log/log.h"
#include <unistd.h>
#include "app_serial.h"

static int init_bt(Device *device) {
    // 初始化串口   波特率 9600 非阻塞
    app_serial_init(device);

    // 将串口改为非阻塞模式
    app_serial_setBlock(device, 0);
    app_serial_flush(device);

    // 判断蓝牙是否可用
    if (app_bt_status(device) == 0) { // 可用 =》 蓝牙的波特率就是9600
        app_bt_setBaudRate(device, BT_BR_115200); // 改波特率为115200
        app_bt_rename(device, "atguigu"); // 重命名
     
        app_bt_reset(device); // 重启蓝牙
        sleep(2); // 等待重启完成
    }

    // 蓝牙波特率已经是115200， 而串口波特率是9600
    // 将串口波特率改为115200
    app_serial_setBaudRate(device, BR_115200);
    app_serial_flush(device); // 让修改生效

    // 判断蓝牙是否可用
    if (app_bt_status(device) != 0) {
        log_error("蓝牙初始化失败");
        return -1;
    }
    log_debug("蓝牙初始化成功");

    app_bt_setNetId(device, "1234"); // 设置组网id  每个组不同， 同一个组相同
    app_bt_setMaddr(device, "0101"); // 设置MACh地域 组内不同， 不同的组可以相同

    // 将串口改为阻塞模式
    app_serial_setBlock(device, 1);
    app_serial_flush(device);

    return 0;
}

int app_bt_init(Device *device)
{

    // 将蓝牙数据与字符数组的转换函数注册到设备
    device->pre_write = app_bt_preWrite;
    device->post_read = app_bt_postRead;

    // 初始化蓝牙配置
    return init_bt(device);
}

/*
字符数组消息:
    例子：1 2 3 XX abc
    格式：conn_type id_len msg_len id msg
蓝牙发送数据格式例子：
    例子：41 54 2b 4d 45 53 48 00 ff ff 61 62 63 0d 0a
    41 54 2b 4d 45 53 48 00： AT+MESH（固定头部）
    ff ff: 对端的MADDR（如果是FFFF代表群发）
    61 62 63: 要发送的数据（不超过12字节）
    0d 0a：\r\n（固定结尾）
    AT+MESH XX abc \r\n
*/
int app_bt_preWrite(char *data, int len)
{
    // 检查len的合法性
    if (len < 6)
    {
        log_error("数据长度不够");
        return -1;
    }

    // 蓝牙数据的长度
    int blue_len = 12 + data[2];
    char blue_data[blue_len];
    // 向蓝牙数据数组中添加各部分数据
    // AT+MESH
    memcpy(blue_data, "AT+MESH", 8);
    // 对端id
    memcpy(blue_data + 8, data + 3, 2);
    // 要发送的数据msg
    memcpy(blue_data + 10, data + 5, data[2]);
    // \r\n
    memcpy(blue_data + 10 + data[2], "\r\n", 2);

    // 清空data
    memset(data, 0, len);
    // 将blue_data拷贝到data
    memcpy(data, blue_data, blue_len);

    // 返回蓝牙数据的长度
    return blue_len;
}

static char read_buf[1024];               // 缓存读取到的蓝牙数据
static int read_len = 0;                  // 缓存数据长度
static char fix_header[2] = {0xf1, 0xdd}; // 固定头部

// 删除指定个数的数据
static void remove_data(int count)
{
    memmove(read_buf, read_buf + count, read_len - count);
    read_len -= count;
}

/*
接收方得到数据（3 + [2]）：f1 dd 07 23 23 ff ff 41 42 43
    f1 dd : 固定的头部
    07： 之后数据的长度（5-16之间）
    23 23：对端（发送方）的MADDR
    ff ff: 我的MADDR或ffff(群发)
    41 42 43：发送的数据
处理后的数据格式：conn_type id_len msg_len id msg
*/
int app_bt_postRead(char *data, int len)
{
    //  将data添加到缓存中
    memcpy(read_buf + read_len, data, len);
    read_len += len;

    // 检查数据长度（不能小于8）
    if (read_len < 8)
    {
        log_debug("数据长度不够，继续读取");
        return 0; // 返回0表示数据不完整， 继续读取
    }

    // 遍历查找接收到蓝牙数据
    int i;
    for (i = 0; i < read_len - 7; i++)
    {
        if (memcmp(fix_header, read_buf + i, 2) == 0)
        {
            if (i > 0)
            { // 前面遍历过的都是无效数据， 删除无效数据
                remove_data(i);
                // 再次检查数据长度
                if (read_len < 8)
                {
                    log_debug("数据长度不够，继续读取");
                    return 0;
                }
            }
            // 计算蓝牙数据的长度
            int blue_len = 3 + read_buf[2];
            // 检查蓝牙数据长度是否合法
            if (read_len < blue_len)
            {
                log_debug("数据长度不够，继续读取");
                return 0;
            }
            // 生成字符数组消息：conn_type id_len msg_len id msg
            // f1 dd 07 23 23 ff ff 41 42 43
            memset(data, 0, len);
            data[0] = 1;                             // conn_type
            data[1] = 2;                             // id_len
            data[2] = blue_len - 7;                  // msg_len
            memcpy(data + 3, read_buf + 3, 2);       // id
            memcpy(data + 5, read_buf + 7, data[2]); // msg

            // 将当前的蓝牙数据从缓存中移除
            remove_data(blue_len);

            // 返回字符数组消息的长度
            return 5 + data[2];
        }
    }

    // 删除遍历过的无效数据
    if (i > 0)
    {
        remove_data(i);
    }

    return 0;
}

// 等待ack
int wait_ack(int fd) {
    // 等待一会（50ms）
    usleep(50* 1000);
    // 读取ack
    char read_buf[4];
    read(fd, read_buf, 4);
    if (memcmp(read_buf, "OK\r\n", 4) != 0) {
        log_error("等待接收ACK失败");
        return -1;
    }
    return 0;
}

int app_bt_status(Device *device)
{
    // 准备命令
    char *cmd = "AT\r\n";
    // 发送命令
    write(device->fd, cmd, strlen(cmd));
    // 获取ack
    return wait_ack(device->fd);
}

int app_bt_rename(Device *device, char *name)
{
    // 准备命令
    char cmd[20];
    sprintf(cmd, "AT+NAME%s\r\n", name);
    // 发送命令
    write(device->fd, cmd, strlen(cmd));
    // 获取ack
    return wait_ack(device->fd);
}

int app_bt_setBaudRate(Device *device, BT_BaudRate baudRate)
{
    // 准备命令
    char cmd[20];
    sprintf(cmd, "AT+BAUD%c\r\n", baudRate);
    // 发送命令
    write(device->fd, cmd, strlen(cmd));
    // 获取ack
    return wait_ack(device->fd);
}

int app_bt_reset(Device *device)
{
    // 准备命令
    char *cmd = "AT+RESET\r\n";
    // 发送命令
    write(device->fd, cmd, strlen(cmd));
    // 获取ack
    return wait_ack(device->fd);
}

int app_bt_setNetId(Device *device, char *netId)
{
    // 准备命令
    char cmd[20];
    sprintf(cmd, "AT+NETID%s\r\n", netId);
    // 发送命令
    write(device->fd, cmd, strlen(cmd));
    // 获取ack
    return wait_ack(device->fd);
}

int app_bt_setMaddr(Device *device, char *maddr)
{
    // 准备命令
    char cmd[20];
    sprintf(cmd, "AT+MADDR%s\r\n", maddr);
    // 发送命令
    write(device->fd, cmd, strlen(cmd));
    // 获取ack
    return wait_ack(device->fd);
}
